package com.example.shrio.conf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

import com.example.shrio.AdminUserShiroRealm;
import com.example.shrio.CommonUserShiroRealm;
import com.example.shrio.MyExceptionHandler;

@Configuration
public class ShiroConfig {

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 注意过滤器配置顺序 不能颠倒
		// 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了，登出后跳转配置的loginUrl
		filterChainDefinitionMap.put("/logout", "logout");
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/admin/home/login", "anon");
		filterChainDefinitionMap.put("/common/home/login", "anon");
		filterChainDefinitionMap.put("/external/release/**", "anon");
		filterChainDefinitionMap.put("/**", "authc");
		// 配置shiro默认登录界面地址，前后端分离中登录界面跳转应由前端路由控制，后台仅返回json数据
		shiroFilterFactoryBean.setLoginUrl("/shrio/unauth");
		// 登录成功后要跳转的链接
		// shiroFilterFactoryBean.setSuccessUrl("/index");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	@Bean
	public AdminUserShiroRealm myShiroRealm() {
		AdminUserShiroRealm myShiroRealm = new AdminUserShiroRealm();
		return myShiroRealm;
	}

	@Bean
	public CommonUserShiroRealm myUserShiroRealm() {
		CommonUserShiroRealm myUserShiroRealm = new CommonUserShiroRealm();
		return myUserShiroRealm;
	}

	@Bean
	public CustomizedModularRealmAuthenticator myRealmAuthenticator() {
		CustomizedModularRealmAuthenticator myRealmAuthenticator = new CustomizedModularRealmAuthenticator();
		return myRealmAuthenticator;
	}

	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setAuthenticator(myRealmAuthenticator());
		// securityManager.setRealm(myShiroRealm());
		Collection<Realm> realms = new ArrayList<>();
		realms.add(myShiroRealm());
		realms.add(myUserShiroRealm());
		securityManager.setRealms(realms);

		// 自定义session管理 使用redis
		securityManager.setSessionManager(sessionManager());
		// 自定义缓存实现 使用redis
		// securityManager.setCacheManager(cacheManager());
		return securityManager;
	}

	// 自定义sessionManager
	@Bean
	public SessionManager sessionManager() {
		MySessionManager mySessionManager = new MySessionManager();
		mySessionManager.setSessionFactory(sessionFactory());
		mySessionManager.setSessionDAO(redisSessionDAO());
		mySessionManager.setGlobalSessionTimeout(3600000);
		mySessionManager.setDeleteInvalidSessions(true);
		return mySessionManager;
	}

	@Bean
	public ShiroSessionFactory sessionFactory() {

		return new ShiroSessionFactory();
	}

	@Bean
	public RedisShiroSessionDAO redisSessionDAO() {
		RedisShiroSessionDAO redisSessionDAO = new RedisShiroSessionDAO();
		return redisSessionDAO;
	}

	/**
	 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
	 * 
	 * @return
	 */
	@Bean
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		advisorAutoProxyCreator.setProxyTargetClass(true);
		return advisorAutoProxyCreator;
	}

	/**
	 * 开启aop注解支持
	 * 
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

	/**
	 * 注册全局异常处理
	 * 
	 * @return
	 */
	@Bean(name = "exceptionHandler")
	public HandlerExceptionResolver handlerExceptionResolver() {
		return new MyExceptionHandler();
	}

}
